home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Light ROM 1
/
LIGHT-ROM 1 (Amiga Library Services)(1994).iso
/
ffdisks
/
d895.lha
/
FMsynth
/
src
/
Source.lha
/
FMsynth.mod
< prev
next >
Wrap
Text File
|
1993-06-27
|
77KB
|
2,388 lines
(*-------------------------------------------------------------------------
:Program. FMsynth.mod
:Contents. 6 Operator FM-Syntheziser
:Author. Christian Stiens
:Address. Snail-Mail: E-Mail:
:Address. Heustiege 2 UUCP: Christian_Stiens@ouzonix.bo.open.de
:Address. D-59348 Lüdinghausen FIDO: 2:243/4802.25
:Copyright. Giftware, © 93 Christian Stiens
:Language. Oberon-2
:Translator. Amiga Oberon 3.01d
:History. V1.0, 26-Feb-93: first release
:History. V1.1, 21-Jun-93: keymap now compatible with ProTracker
:History. 21-Jun-93: sound can be > 99999 Bytes
:History. 21-Jun-93: uses "setthresh" no more
:History. 23-Jun-93: AutoCalc
:History. 26-Jun-93: Chords
:Imports. AudioSupport, IntuiSupport, MyFileReq, IntuiPointer
-------------------------------------------------------------------------*)
MODULE FMsynth;
(* $JOIN sintab.o *)
IMPORT
arg := Arguments,
as := AudioSupport,
c := Conversions,
cia := Cia,
d := Dos,
e := Exec,
fr := MyFileReq,
g := Graphics,
hw := Hardware,
I := Intuition,
ie := InputEvent,
ip := IntuiPointer,
is := IntuiSupport,
ffp := MathFFP,
trans:= MathTrans,
ol := OberonLib,
rq := Requests,
str := Strings,
u := Utility,
SYS := SYSTEM;
CONST
ver = "\o$VER: fmsynth 1.1 (26.6.93)";
(* $DataChip+ *)
beep = "\x00\x7F\x00\x80";
TYPE
Algorithm = STRUCT
numLines : INTEGER;
line : ARRAY 15 OF STRUCT mod,car: SHORTINT END;
END;
Operator = STRUCT
scR : SHORTINT;
scL : SHORTINT;
r,l : ARRAY 4 OF SHORTINT;
freq : REAL;
outp : SHORTINT;
mode : SHORTINT;
END;
LFO = STRUCT
wave : SHORTINT; (* LFOWaves *)
spd,del : SHORTINT;
amd,pmd : SHORTINT;
END;
CONST
maxPM = 5.0E5;
intPerSec = 110;
CONST
numChords = 8;
TYPE
ChordTable = ARRAY numChords,3 OF REAL;
CONST
f0 = 1;
f3 = 1.189207;
f4 = 1.259921;
f5 = 1.334840;
f6 = 1.414214;
f7 = 1.498307;
f10 = 1.781797;
f11 = 1.887749;
CONST
chordTable = ChordTable(f0,f0,f0,
f0,f4,f7,
f0,f3,f7,
f0,f3,f6,
f0,f5,f7,
f0,f4,f10,
f0,f4,f11,
f0,f3,f10);
CONST
sin=0; tri=1; down=2; up=3; sqr=4; (* LFOWaves *)
end=0; keyDown=1; keyUp=2; (* State *)
poly=0; mono=1; (* Mode *)
car=0; mod=1; none=2;
ratio=0; fixed=1; (* Operator.mode *)
pfH = {I.freeHoriz,I.propBorderless};
pfV = {I.freeVert,I.propBorderless};
(*----- Gadget-IDs -----*)
O1=1;O2=2;O3=3;O4=4;O5=5;O6=6;SR=7;SL=8;
R1=9;R2=10;R3=11;R4=12;L1=13;L2=14;L3=15;L4=16;
OL=17;FR=18;WA=19;SP=20;DE=21;AM=22;PM=23;
M1=24;M2=25;M3=26;M4=27;M5=28;M6=29;
C1=30;C2=31;C3=32;C4=33;C5=34;C6=35;
LN=36;RR=37;CS=38;TP=39;OS=40;OK=41;CA=42;
B1=43;B2=44;B3=45;B4=46;B5=47;CL=48;
OM=49;FB=50;MD=51;FL=52;PR=53;
VAR (*--- Globals ----*)
scr : I.ScreenPtr;
scrtitle : ARRAY 80 OF CHAR;
win,win2 : I.WindowPtr;
req : I.RequesterPtr;
rp : g.RastPortPtr;
vp : g.ViewPortPtr;
pal : BOOLEAN;
oldfltstate : BOOLEAN;
mes : I.IntuiMessage;
menu : I.MenuPtr;
me : d.ProcessPtr;
oldWindowPtr : I.WindowPtr;
filePath : e.STRING;
file : d.FileHandlePtr;
op : ARRAY 6 OF Operator;
opNr : SHORTINT;
lfo : LFO;
lfoTab : ARRAY 256 OF SHORTINT;
lfoPic : UNTRACED POINTER TO SYS.BYTE;
lfoImg : I.ImagePtr;
fmImg : I.ImagePtr;
fmPic : UNTRACED POINTER TO SYS.BYTE;
mixPic : UNTRACED POINTER TO SYS.BYTE;
mixImg : I.ImagePtr;
zifPic : UNTRACED POINTER TO SYS.BYTE;
zifImg : I.ImagePtr;
algo : Algorithm;
isCarrier : ARRAY 6 OF BOOLEAN;
output : INTEGER;
maxoutp : INTEGER;
disabled : BOOLEAN;
key : ARRAY 128 OF SHORTINT;
period : ARRAY 36 OF REAL;
channel : ARRAY 36 OF SHORTINT;
rRate : SHORTINT;
mode : SHORTINT;
soundBuf : SYS.ADDRESS;
soundLen : LONGINT;
lenHi : LONGINT;
oneShotHi : LONGINT;
repeatHi : LONGINT;
shiftOct : INTEGER;
chord : INTEGER;
filter : BOOLEAN;
autoCalc : BOOLEAN;
transp : REAL;
feedback : SHORTINT;
int : e.Interrupt;
intOn : BOOLEAN;
volTemp : REAL;
perTemp : REAL;
Per : INTEGER;
vol,per : ARRAY 4 OF REAL;
deltaVol : REAL;
state : ARRAY 4 OF SHORTINT;
delay : ARRAY 4 OF INTEGER;
lfoArg : ARRAY 4 OF INTEGER;
lfoInc : INTEGER;
i,id : INTEGER;
lastCar : SHORTINT;
lastMod : SHORTINT;
lastWas : SHORTINT;
flag : BOOLEAN;
keyCode : INTEGER;
selGad : I.GadgetPtr;
actPropGad : I.GadgetPtr;
code : INTEGER;
octave : INTEGER;
chan : SHORTINT;
lockreq : I.Requester;
sinTab ["_SinTab"] : ARRAY 8192 OF SHORTINT;
(*----- Gadgets -----*)
gadOp : ARRAY 7 OF I.GadgetPtr;
gadEG : ARRAY 8 OF I.GadgetPtr; knobEG : ARRAY 8 OF I.Image;
gadAlgM : ARRAY 7 OF I.GadgetPtr;
gadAlgC : ARRAY 7 OF I.GadgetPtr;
gadFreq : I.GadgetPtr;
gadLen : I.GadgetPtr;
gadOutp : I.GadgetPtr; knobOutp : I.Image;
gadLFOs : I.GadgetPtr; knobLFOs : I.Image;
gadLFOd : I.GadgetPtr; knobLFOd : I.Image;
gadLFOa : I.GadgetPtr; knobLFOa : I.Image;
gadLFOp : I.GadgetPtr; knobLFOp : I.Image;
gadLFOw : I.GadgetPtr;
gadScR : I.GadgetPtr; knobScR : I.Image;
gadScL : I.GadgetPtr; knobScL : I.Image;
gadRel : I.GadgetPtr; knobRel : I.Image;
gadCalc : I.GadgetPtr;
gadTsp : I.GadgetPtr;
gadOffs : I.GadgetPtr; knobPlot : I.Image;
gadOk : I.GadgetPtr;
gadCncl : I.GadgetPtr;
gadBuf : ARRAY 6 OF I.GadgetPtr;
gadClr : I.GadgetPtr;
gadFeed : I.GadgetPtr;
gadFlt : I.GadgetPtr;
gadMode : I.GadgetPtr;
gadOM : I.GadgetPtr;
gadPer : I.GadgetPtr;
(*------------------------------------------------------------------------*)
PROCEDURE LFOPics; (* $EntryExitCode- *)
BEGIN SYS.INLINE
(03C00H,04200H,08100H,08100H,00081H,00081H,00042H,0003CH,
00800H,01400H,02200H,04101H,08082H,00044H,00028H,00010H,
08100H,0C180H,0A140H,09120H,08910H,08508H,08304H,08102H,
00102H,00306H,0050AH,00912H,01122H,02142H,04182H,08102H,
0FF00H,08100H,08100H,08100H,00102H,00102H,00102H,001FEH)
END LFOPics;
(*------------------------------------------------------------------------*)
PROCEDURE MixPics; (* $EntryExitCode- *)
BEGIN SYS.INLINE(
0C5D2H, 0AA95H, 0AA95H, 0CE95H, 0AA95H, 0AA92H,
0EAB6H, 08AA5H, 0C935H, 08925H, 08AA5H, 08AB6H,
0A492H, 0EAD5H, 0EAD5H, 0AAB5H, 0AAB5H, 0A492H,
0C491H, 0AA8AH, 0AA84H, 0CA84H, 08A84H, 084E4H,
00490H, 00AD0H, 00AD0H, 00AB0H, 00AB0H, 00490H,
009DCH, 01510H, 01598H, 01510H, 01510H, 00910H)
END MixPics;
(*------------------------------------------------------------------------*)
PROCEDURE Ziffern; (* $EntryExitCode- *)
BEGIN SYS.INLINE(
0C000H, 0C000H, 0C000H, 0C000H, 0C000H, (* 0 *)
04000H, 0C000H, 04000H, 04000H, 04000H, (* 1 *)
0C000H, 04000H, 0C000H, 08000H, 0C000H, (* 2 *)
0C000H, 04000H, 0C000H, 04000H, 0C000H, (* 3 *)
08000H, 08000H, 0C000H, 04000H, 04000H, (* 4 *)
0C000H, 08000H, 0C000H, 04000H, 0C000H, (* 5 *)
0C000H, 08000H, 0C000H, 0C000H, 0C000H, (* 6 *)
0C000H, 04000H, 04000H, 04000H, 04000H, (* 7 *)
0C000H, 0C000H, 08000H, 0C000H, 0C000H, (* 8 *)
0C000H, 0C000H, 0C000H, 04000H, 0C000H) (* 9 *)
END Ziffern;
(*------------------------------------------------------------------------*)
PROCEDURE FMPic; (* $EntryExitCode- *)
BEGIN SYS.INLINE(
(* [0] *)
0FF80H,00007H,0F03FH,0FFFFH,0FFFFH,0FFFEH,01FFFH,0FFFFH,
0FFBFH,0FEF7H,0F7BFH,0FFFFH,0FFFFH,0F878H,0DFFFH,0FFFFH,
0FFBFH,0FFF1H,0E78FH,0FFFFH,0FFFFH,0F373H,0C7FFH,0FFFFH,
0FF9FH,0FF79H,0EF0FH,0FFFFH,0FFFFH,0E717H,0C7FFH,0FFFFH,
0FFCFH,08738H,0CF0FH,0FFFFH,0FFFFH,0CF17H,0C7FFH,0FFFFH,
0FFEFH,0833CH,0DF00H,01018H,07843H,09F03H,0C0FFH,0FFFFH,
0FFEFH,0803CH,01F0FH,0C7C3H,02319H,03FEBH,0C67FH,0FFFFH,
0FFEFH,0903EH,03F1FH,0EFE7H,08F3CH,07FE3H,0DF3FH,0FFFFH,
0FFEFH,0983EH,03F3FH,0EFE7H,09FFEH,01F03H,0FF9FH,0FFFFH,
0FFEFH,0F8BFH,07F3EH,047C3H,0BFFEH,01F03H,0FF8FH,0FFFFH,
0FFEFH,0F8BFH,0FF3FH,003C7H,01F7EH,01F03H,0EF8FH,0FFFFH,
0FFEFH,0F8B7H,0EF3FH,083E7H,01E3EH,01F1BH,0C78FH,0FFFFH,
0FFEFH,098B7H,0EF1FH,0C1EEH,01E3EH,01F1BH,0C78FH,0FFFFH,
0FFEFH,090B3H,0CF0FH,0E5FEH,01E3EH,01F1BH,0C78FH,0FFFFH,
0FFEFH,080B3H,0CF07H,0E0FEH,01E3EH,01F0BH,0C78FH,0FFFFH,
0FFCFH,08031H,08F33H,0E2FCH,01E3EH,01F63H,0C78FH,0FFFFH,
0FF9FH,0C071H,08F3BH,0E2FCH,01E3EH,01FE7H,0C78FH,0FFFFH,
0FFBFH,0E6F9H,09F9FH,0C27CH,03F3FH,00FCFH,0EFCFH,0FFFFH,
0FFBFH,0E2F8H,01F8FH,08078H,01E1EH,0078FH,0EFC7H,0FFFFH,
0FF80H,00200H,00000H,00378H,04000H,01000H,00007H,0FFFFH,
0FFE0H,00380H,00000H,00770H,06000H,01800H,00007H,0FFFFH,
0FFE0H,00380H,0F008H,007F0H,0F030H,03C08H,00007H,0FFFFH,
0FFFFH,0FFFFH,0FFFFH,0F7E0H,0FFFFH,0FFFFH,0FFFFH,0FFFFH,
0FFFFH,0FFFFH,0FFFFH,0F3C1H,0FFFFH,0FFFFH,0FFFFH,0FFFFH,
0FFFFH,0FFFFH,0FFFFH,0F801H,0FFFFH,0FFFFH,0FFFFH,0FFFFH,
0FFFFH,0FFFFH,0FFFFH,0FC03H,0FFFFH,0FFFFH,0FFFFH,0FFFFH,
0FFFFH,0FFFFH,0FFFFH,0FE07H,0FFFFH,0FFFFH,0FFFFH,0FFFFH,
(* [1] *)
0007FH,0FFF8H,00FC0H,00000H,00000H,00001H,0E000H,00000H,
0007FH,0FFF8H,00FC0H,00000H,00000H,00787H,0E000H,00000H,
0007FH,0FFFCH,01FC0H,00000H,00000H,00F8FH,0E000H,00000H,
0007FH,0FFFCH,01FC0H,00000H,00000H,01F8FH,0E000H,00000H,
0003FH,0FFFEH,03F80H,00000H,00000H,03F8FH,0E000H,00000H,
0001FH,0CFFEH,03F9FH,0EFE7H,087BCH,07FFFH,0EF00H,00000H,
0001FH,0FFFFH,07FBFH,0FFFFH,0DFFEH,0FFF7H,0FF80H,00000H,
0001FH,0FC7FH,07FFFH,0FFFFH,0FFFFH,0FFF7H,0FFC0H,00000H,
0001FH,0FC7FH,0FFFFH,0FFFFH,0FFFFH,0FFF7H,0FFC0H,00000H,
0001FH,0FC7FH,0FFFFH,0FFFFH,0FFFFH,03F87H,0FFC0H,00000H,
0001FH,0FC7FH,0FFFFH,0EFFFH,0FFFFH,03F87H,0FFC0H,00000H,
0001FH,0FC7FH,0FFFFH,0E7FFH,0BFFFH,03F87H,0FFC0H,00000H,
0001FH,0FC7FH,0FFFFH,0F7FFH,0BF7FH,03F87H,0EFC0H,00000H,
0001FH,0FC7FH,0FFBFH,0F3FFH,03F7FH,03F87H,0EFC0H,00000H,
0001FH,0F87FH,0FFFFH,0F3FFH,03F7FH,03FF7H,0EFC0H,00000H,
0003FH,0E0FFH,0FFFFH,0F1FFH,03F7FH,03FFFH,0EFC0H,00000H,
0007FH,0F1FFH,0FFFFH,0F1FEH,07FFFH,0BFFFH,0FFE0H,00000H,
0007FH,0F1FFH,0FFFFH,0F1FEH,07FFFH,0BFFFH,0FFE0H,00000H,
0007FH,0F1FFH,0FFFFH,0E7FEH,07FFFH,09FFFH,0FFE0H,00000H,
0007FH,0F1FCH,03FDFH,0CFFCH,03F3FH,00FDFH,0FFE0H,00000H,
00000H,00000H,00000H,00FFCH,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,00FF8H,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,00FF8H,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,00FF0H,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,007E0H,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,00000H,00000H,00000H,00000H,00000H,
00000H,00000H,00000H,00000H,00000H,00000H,00000H,00000H);
END FMPic;
(*------------------------------------------------------------------------*)
PROCEDURE VKnob; (* $EntryExitCode- *)
BEGIN
SYS.INLINE(
07800H,0FC00H,00000H,0FC00H,07800H,
0FC00H,0FC00H,0FC00H,0FC00H,0FC00H)
END VKnob;
(*------------------------------------------------------------------------*)
PROCEDURE HKnob; (* $EntryExitCode- *)
BEGIN
SYS.INLINE(
05000H,0D800H,0D800H,0D800H,0D800H,05000H,
0F800H,0F800H,0F800H,0F800H,0F800H,0F800H)
END HKnob;
(*------------------------------------------------------------------------*)
PROCEDURE ToChipMem(adr:e.ADDRESS; size:LONGINT; check:BOOLEAN): e.ADDRESS;
VAR newAdr: e.ADDRESS;
p1,p2: UNTRACED POINTER TO SYS.BYTE;
BEGIN
IF check & (e.chip IN e.TypeOfMem(adr)) THEN RETURN adr END;
INCL(ol.MemReqs,e.chip);
ol.New(newAdr,size);
EXCL(ol.MemReqs,e.chip);
p1 := adr; p2 := newAdr;
e.CopyMem(p1^,p2^,size);
RETURN newAdr
END ToChipMem;
(*------------------------------------------------------------------------*)
PROCEDURE LockWindow(win: I.WindowPtr);
BEGIN
I.InitRequester(lockreq);
lockreq.width := 1;
lockreq.height := 1;
lockreq.backFill := SHORT(SHORT(g.ReadPixel(win.rPort,0,0)));
IF ~ I.Request(SYS.ADR(lockreq),win) THEN HALT(20) END;
END LockWindow;
(*------------------------------------------------------------------------*)
PROCEDURE UnLockWindow(win:I.WindowPtr);
BEGIN
I.EndRequest(SYS.ADR(lockreq),win);
END UnLockWindow;
(*------------------------------------------------------------------------*)
PROCEDURE Request(hail,pos,neg:ARRAY OF CHAR): BOOLEAN; (* $CopyArrays- *)
VAR
txt0,t : I.IntuiTextPtr;
posGad : I.GadgetPtr;
BEGIN
IF req=NIL THEN
txt0 := is.CreateIntuiText(2,0,g.jam1,0,10,NIL,"", is.CreateIntuiText(3,0,g.jam1,0,9,NIL,"",NIL));
is.whitePen := 3; is.blackPen := 2;
is.gadgetFrontPen := 3; is.gadgetBackPen := 1;
gadOk := is.CreateBoolGadget(0,12,31,55,12," ",is.autoBorder,NIL,is.stdGad,is.stdAct+{I.endGadget});
gadCncl := is.CreateBoolGadget(0,85,31,55,12," ",gadOk.gadgetRender,NIL,is.stdGad,is.stdAct+{I.endGadget});
req := is.CreateRequester(85,75,150,50,0,0,is.autoBorder,txt0,{},1);
is.AddReqGadget(req,gadOk);
is.AddReqGadget(req,gadCncl);
END;
t := req.reqText; t.iText := SYS.ADR(hail); t.leftEdge := 76-SHORT(str.Length(hail))*4;
t := t.nextText; t.iText := SYS.ADR(hail); t.leftEdge := 75-SHORT(str.Length(hail))*4;
IF pos[0] # 0X THEN
t := req.reqGadget.nextGadget.gadgetText;
t.iText := SYS.ADR(pos); t.leftEdge := 29-SHORT(str.Length(pos))*4;
END;
t := req.reqGadget.gadgetText;
t.iText := SYS.ADR(neg); t.leftEdge := 29-SHORT(str.Length(neg))*4;
IF pos[0]=0X THEN
posGad := req.reqGadget.nextGadget;
req.reqGadget.nextGadget := NIL;
END;
IF ~I.Request(req,win) THEN RETURN TRUE END;
REPEAT is.GetIMsg(win,mes,TRUE) UNTIL I.gadgetUp IN mes.class;
IF pos[0]=0X THEN
req.reqGadget.nextGadget := posGad
END;
RETURN mes.iAddress = gadOk;
END Request;
(*------------------------------------------------------------------------*)
PROCEDURE InitKnobs;
VAR i:INTEGER;
BEGIN
(*--- VertKnobs ---*)
knobOutp.leftEdge := 0;
knobOutp.topEdge := 0;
knobOutp.width := 6;
knobOutp.height := 5;
knobOutp.depth := 2;
knobOutp.imageData := ToChipMem(SYS.VAL(SYS.ADDRESS,VKnob),20,TRUE);
knobOutp.planePick := SHORTSET{0,1};
knobOutp.planeOnOff := SHORTSET{};
knobOutp.nextImage := NIL;
FOR i:=0 TO 7 DO
knobEG[i] := knobOutp
END;
knobScL := knobOutp;
knobScR := knobOutp;
(*--- HorizKnobs ---*)
knobLFOs.leftEdge := 0;
knobLFOs.topEdge := 0;
knobLFOs.width := 5;
knobLFOs.height := 6;
knobLFOs.depth := 2;
knobLFOs.imageData := ToChipMem(SYS.VAL(SYS.ADDRESS,HKnob),24,TRUE);
knobLFOs.planePick := SHORTSET{0,1};
knobLFOs.planeOnOff := SHORTSET{};
knobLFOs.nextImage := NIL;
knobLFOd := knobLFOs;
knobLFOa := knobLFOs;
knobLFOp := knobLFOs;
knobPlot := knobLFOs;
knobRel := knobLFOs;
END InitKnobs;
(*------------------------------------------------------------------------*)
PROCEDURE StringToReal(s: ARRAY OF CHAR; VAR x: REAL): BOOLEAN; (* $CopyArrays- *)
VAR v,w,z : LONGINT;
i : INTEGER;
p : BOOLEAN;
minus : BOOLEAN;
f : REAL;
BEGIN
i := 0; v := 0; w := 0; p := FALSE; f := 1; minus := FALSE;
WHILE (i < LEN(s)) & (s[i] # 0X) DO
IF s[i] = "." THEN
p := TRUE
ELSIF s[i] = "-" THEN
minus := TRUE
ELSE
IF (s[i] >= "0") & (s[i] <= "9") THEN
z := ORD(s[i]) - ORD("0");
IF p THEN f := f / 10; w := w * 10 + z ELSE v := v * 10 + z END;
END;
END; INC(i)
END;
x := v + w * f;
IF minus THEN x := -x END;
RETURN TRUE;
END StringToReal;
(*------------------------------------------------------------------------*)
PROCEDURE RealToString(x: REAL; VAR s: ARRAY OF CHAR; n: INTEGER): BOOLEAN;
VAR i : INTEGER;
w : REAL;
v,f,z: LONGINT;
flag : BOOLEAN;
ovfl : BOOLEAN;
zn : LONGINT;
p : BOOLEAN;
PROCEDURE Char(ch: CHAR);
BEGIN
IF i < LEN(s) THEN
s[i] := ch;
INC(i)
ELSE
IF ~p THEN ovfl := TRUE END;
END;
END Char;
BEGIN (* RealToString *)
i := 0; ovfl := FALSE; flag := FALSE; p := FALSE;
IF x<0 THEN Char("-"); x:=-x END;
zn := 1;
WHILE n>0 DO zn := zn * 10; DEC(n) END;
x := x + 0.5/zn; (* Round *)
v := ENTIER(x);
w := x - v; (* Trunc *)
f := 1000000000;
REPEAT
z := v DIV f;
IF z # 0 THEN flag := TRUE END;
IF flag THEN Char(CHR(z+ORD("0"))) END;
v := v - z * f; f := f DIV 10
UNTIL f = 0;
p := TRUE;
Char(".");
w := w * zn; v := ENTIER(w); f := zn;
WHILE f >= 10 DO
f := f DIV 10;
z := v DIV f;
Char(CHR(z+ORD("0")));
v := v - z * f;
END;
IF i < LEN(s) THEN s[i] := 0X END;
RETURN ~ ovfl
END RealToString;
(*------------------------------------------------------------------------*)
PROCEDURE IntPerSec(ints: INTEGER);
VAR wert : INTEGER;
eClock : LONGINT;
BEGIN
(* $RangeChk- $OvflChk- *)
IF e.exec.libNode.version >= 37 THEN
eClock := e.exec.eClockFrequency
ELSE
eClock := 712644;
END;
wert := SHORT(ENTIER(eClock/ints+0.5));
hw.ciaa.talo := SHORT(SYS.VAL(INTEGER,SYS.VAL(SET,wert) * {0..7}));
hw.ciaa.tahi := SHORT(SYS.LSH(wert,-8));
INCL(hw.ciaa.cra,hw.craLoad);
(* $RangeChk= $OvflChk= *)
END IntPerSec;
(*------------------------------------------------------------------------*)
PROCEDURE SetTimer(start: BOOLEAN);
BEGIN
IF start THEN
IntPerSec(intPerSec);
INCL(hw.ciaa.cra,hw.craStart)
ELSE
EXCL(hw.ciaa.cra,hw.craStart)
END;
END SetTimer;
(*------------------------------------------------------------------------*)
PROCEDURE Print(rp:g.RastPortPtr; x,y:INTEGER; str:ARRAY OF CHAR);
(* $CopyArrays- *)
VAR i:INTEGER;
BEGIN
i := 0;
WHILE (i < LEN(str)) & (str[i] # 0X) DO INC(i) END;
g.SetDrMd(rp,g.jam1);
g.Move(rp,x+1,y+1);
g.SetAPen(rp,2);
g.Text(rp,str,i);
g.SetAPen(rp,3);
g.Move(rp,x,y);
g.Text(rp,str,i);
END Print;
(*------------------------------------------------------------------------*)
PROCEDURE Box(rp:g.RastPortPtr; x,y,a,b:INTEGER;
out:BOOLEAN;fill:INTEGER);
BEGIN
IF fill >= 0 THEN
g.SetAPen(rp,fill);
g.RectFill(rp,x,y,x+a-1,y+b-1)
END;
IF out THEN g.SetAPen(rp,3) ELSE g.SetAPen(rp,2) END;
g.Move(rp,x+a-1,y); g.Draw(rp,x,y); g.Draw(rp,x,y+b-1);
IF out THEN g.SetAPen(rp,2) ELSE g.SetAPen(rp,3) END;
g.Draw(rp,x+a-1,y+b-1); g.Draw(rp,x+a-1,y+1);
END Box;
(*------------------------------------------------------------------------*)
PROCEDURE PrintNumber(rp:g.RastPortPtr; x,y: INTEGER; num: INTEGER);
VAR z: ARRAY 3 OF INTEGER;
adr: UNTRACED POINTER TO SYS.BYTE;
i,j: INTEGER;
BEGIN
z[2] := num DIV 100;
z[1] := num MOD 100 DIV 10;
z[0] := num MOD 10;
IF num >= 100 THEN j := 3
ELSIF num >= 10 THEN j := 2
ELSE j := 1
END;
g.SetAPen(rp,1);
CASE j OF
1: g.RectFill(rp,x-6,y,x-2,y+4) |
2: g.RectFill(rp,x-6,y,x-5,y+4)
ELSE END;
FOR i:=0 TO j-1 DO
adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,Ziffern) + z[i]*10);
e.CopyMem(adr^,zifPic^,10);
I.DrawImage(rp,zifImg^,x-i*3,y);
END;
END PrintNumber;
(*------------------------------------------------------------------------*)
PROCEDURE Frame(rp:g.RastPortPtr; x,y,a,b:INTEGER);
BEGIN
g.Move(rp,x+a-1,y);
g.Draw(rp,x,y); g.Draw(rp,x,y+b-1);
g.Draw(rp,x+a-1,y+b-1); g.Draw(rp,x+a-1,y+1);
END Frame;
(*------------------------------------------------------------------------*)
PROCEDURE ResetChord;
VAR i: INTEGER;
item: I.MenuItemPtr;
BEGIN
chord := 0;
I.ClearMenuStrip(win);
FOR i := 0 TO numChords-1 DO
item := I.ItemAddress(menu^,I.UIntToLong(I.FullMenuNum(2,1,i)));
IF i=0 THEN INCL(item.flags,I.checked)
ELSE EXCL(item.flags,I.checked) END;
END;
IF I.SetMenuStrip(win,menu^) THEN END;
END ResetChord;
(*------------------------------------------------------------------------*)
PROCEDURE SetUpMenu;
CONST es = LONGSET{};
BEGIN
is.DefMenu("Project",8,0,7*8+2,10,TRUE);
is.DefItem("Load Voice..",0, 0,128,10,0,es,"L",is.stdItem+{I.commSeq});
is.DefItem("Save Voice..",0,10,128,10,0,es,"S",is.stdItem+{I.commSeq});
is.DefItem("Save 8SVX..", 0,20,128,10,0,es,"V",is.stdItem+{I.commSeq});
is.DefItem("New", 0,30,128,10,0,es,"N",is.stdItem+{I.commSeq});
is.DefItem("About", 0,40,128,10,0,es," ",is.stdItem);
is.DefSub( fmImg^, 60,10,170,30,0,es," ",{I.itemEnabled});
is.DefSub(" Version 1.1, © 1993 ",60,40,170,10,0,es," ",is.stdItem-{I.highComp});
is.DefSub(" by Christian Stiens ",60,50,170,10,0,es," ",is.stdItem-{I.highComp});
is.DefSub(" Giftware ",60,60,170,10,0,es," ",is.stdItem-{I.highComp});
is.DefSub(" All Rights Reserved ",60,70,170,10,0,es," ",is.stdItem-{I.highComp});
is.DefItem("Quit", 0,50,128,10,0,es,"Q",is.stdItem+{I.commSeq});
is.DefMenu("Operator",10*8,0,8*8+2,10,TRUE);
is.DefItem("Init", 0, 0,85,10,0,es,"I",is.stdItem+{I.commSeq});
is.DefItem("Store »",0,10,85,10,0,es," ",is.stdItem);
is.DefSub("to 1",60, 0,35,10,0,es," ",is.stdItem);
is.DefSub("to 2",60,10,35,10,0,es," ",is.stdItem);
is.DefSub("to 3",60,20,35,10,0,es," ",is.stdItem);
is.DefSub("to 4",60,30,35,10,0,es," ",is.stdItem);
is.DefSub("to 5",60,40,35,10,0,es," ",is.stdItem);
is.DefSub("to 6",60,50,35,10,0,es," ",is.stdItem);
is.DefItem("Freqency »",0,20,85,10,0,es," ",is.stdItem);
is.DefSub("Double",50, 0,80,10,0,es,"D",is.stdItem+{I.commSeq});
is.DefSub("Halve ",50,10,80,10,0,es,"H",is.stdItem+{I.commSeq});
is.DefMenu("Special",20*8,0,7*8+2,10,TRUE);
is.DefItem("Algorithm »",0, 0,110,10,0,es," ",is.stdItem);
is.DefSub("#0",63, 0,50,10,0,es,"0",is.stdItem+{I.commSeq});
is.DefSub("#1",63,10,50,10,0,es,"1",is.stdItem+{I.commSeq});
is.DefSub("#2",63,20,50,10,0,es,"2",is.stdItem+{I.commSeq});
is.DefSub("#3",63,30,50,10,0,es,"3",is.stdItem+{I.commSeq});
is.DefSub("#4",63,40,50,10,0,es,"4",is.stdItem+{I.commSeq});
is.DefSub("#5",63,50,50,10,0,es,"5",is.stdItem+{I.commSeq});
is.DefSub("#6",63,60,50,10,0,es,"6",is.stdItem+{I.commSeq});
is.DefSub("#7",63,70,50,10,0,es,"7",is.stdItem+{I.commSeq});
is.DefSub("#8",63,80,50,10,0,es,"8",is.stdItem+{I.commSeq});
is.DefSub("#9",63,90,50,10,0,es,"9",is.stdItem+{I.commSeq});
is.DefItem("Chord »",0,10,110,10,0,es," ",is.stdItem);
is.itemLeftEdge := I.lowCheckWidth;
is.DefSub("None",63, 0,48,10,0,-LONGSET{0}," ",is.stdItem+{I.checkIt,I.checked});
is.DefSub("maj", 63,10,48,10,0,-LONGSET{1}," ",is.stdItem+{I.checkIt});
is.DefSub("min", 63,20,48,10,0,-LONGSET{2}," ",is.stdItem+{I.checkIt});
is.DefSub("dim", 63,30,48,10,0,-LONGSET{3}," ",is.stdItem+{I.checkIt});
is.DefSub("sus4",63,40,48,10,0,-LONGSET{4}," ",is.stdItem+{I.checkIt});
is.DefSub("7", 63,50,48,10,0,-LONGSET{5}," ",is.stdItem+{I.checkIt});
is.DefSub("7maj",63,60,48,10,0,-LONGSET{6}," ",is.stdItem+{I.checkIt});
is.DefSub("7min",63,70,48,10,0,-LONGSET{7}," ",is.stdItem+{I.checkIt});
is.itemLeftEdge := 2;
is.DefItem("Set Loop..", 0,20,110,10,0,es,"P",is.stdItem+{I.commSeq});
is.DefItem("Fourier..", 0,30,110,10,0,es,"F",is.stdItem+{I.commSeq});
is.itemLeftEdge := I.lowCheckWidth;
is.DefItem("AutoCalc", 0,40,110,10,0,es,"A",is.stdItem+{I.commSeq,I.menuToggle,I.checkIt});
menu := is.InstallMenuStrip(win);
END SetUpMenu;
(*------------------------------------------------------------------------*)
PROCEDURE DoFileRequest(text:ARRAY OF CHAR;VAR filePath:e.STRING):BOOLEAN; (* $CopyArrays- *)
VAR ok:BOOLEAN;
BEGIN
ip.Busy(win);
LockWindow(win);
fr.defaultLeft := 10;
IF CAP(text[0])#"S" THEN
ok := fr.FileReqWin(text,filePath,win);
ELSE
ok := fr.FileReqWinSave(text,filePath,win);
END;
UnLockWindow(win);
ip.Normal(win);
RETURN ok;
END DoFileRequest;
(*------------------------------------------------------------------------*)
PROCEDURE AddGad(gad: I.GadgetPtr);
BEGIN
is.AddGadget(win,gad);
END AddGad;
(*------------------------------------------------------------------------*)
VAR screenTags: u.Tags3;
PROCEDURE NSProc (ns: I.ExtNewScreenPtr);
BEGIN ns.extension := SYS.ADR(screenTags) END NSProc;
PROCEDURE ^DrawKeyboard;
PROCEDURE SetUpScreen;
TYPE ColorType = ARRAY 4 OF INTEGER;
VAR i,pos : INTEGER;
strPtr : UNTRACED POINTER TO ARRAY 6 OF CHAR;
scrHe : INTEGER;
str : ARRAY 2 OF CHAR;
dispInfo : g.DisplayInfo;
BEGIN
screenTags := u.Tags3(I.saPens,SYS.ADR("\xFF\xFF"),
I.saDisplayID,g.defaultMonitorID+g.loresKey,
u.done,u.done);
scrtitle := "FMsynth oct: 1 name: ";
IF I.int.libNode.version < 36 THEN
pal := g.gfx.normalDisplayRows >= 256;
ELSE
IF g.GetDisplayInfoData(NIL,dispInfo,SIZE(dispInfo),g.dtagDisp,g.palMonitorID+g.loresKey) <= 0 THEN
pal := FALSE
ELSIF dispInfo.notAvailable # 0 THEN
screenTags[1].data := g.ntscMonitorID+g.loresKey;
pal := FALSE;
ELSE
screenTags[1].data := g.palMonitorID+g.loresKey;
pal := TRUE;
END;
END;
IF pal THEN scrHe := 256 ELSE scrHe := 200 END;
scr := is.CreateScreen(scrtitle,(g.gfx.normalDisplayColumns-640) DIV 4,0,320,scrHe,2,{},NSProc);
vp := SYS.ADR(scr.viewPort);
g.LoadRGB4(vp,ColorType(0000H,0AAAH,0555H,0FFFH),4);
win := is.CreateWindow("",0,11,320,scrHe-11,scr,
LONGSET{I.borderless,I.backDrop,I.activate,I.noCareRefresh},
LONGSET{I.gadgetDown,I.gadgetUp,I.mouseMove,I.rawKey,I.menuPick},
NIL);
ip.Normal(win);
me.windowPtr := win;
rp := win.rPort;
InitKnobs;
SetUpMenu;
(*----------- BackGround -------------*)
Box(rp,0,0,320,189,TRUE,1);
(*----------- Operator ---------------*)
Box(rp,8,5,214,85,FALSE,-1);
Print(rp,13,13,"Operator");
Print(rp,100,16,"1 2 3 4 5 6");
FOR i:=1 TO 6 DO
Box(rp,i*16+82,8,12,12,TRUE,-1);
gadOp[i] := is.CreateBoolGadget(O1-1+i,i*16+82,8,12,12,"",NIL,NIL,is.stdGad,is.stdAct);
AddGad(gadOp[i]);
END;
gadScR := is.CreatePropGadget(SR,16,29,6,40,0,128,SYS.ADR(knobScR),I.gadgHNone,is.stdAct+{I.followMouse},pfV);
gadScL := is.CreatePropGadget(SL,28,29,6,40,0,128,SYS.ADR(knobScL),I.gadgHNone,is.stdAct+{I.followMouse},pfV);
Print(rp,15,76,"R");
Print(rp,27,76,"L");
Print(rp,13,86,"KSc");
AddGad(gadScR);
AddGad(gadScL);
FOR i := 0 TO 7 DO
gadEG[i] := is.CreatePropGadget(R1+i,47+10*i+i DIV 4*6,29,6,40,0,128,SYS.ADR(knobEG[i]),I.gadgHNone,is.stdAct+{I.followMouse},pfV);
str[0] := CHR(ORD("1")+i MOD 4); str[1] := 0X;
Print(rp,gadEG[i].leftEdge-1,gadEG[i].topEdge+47,str);
AddGad(gadEG[i]);
END;
Print(rp, 50,86,"Rate");
Print(rp,100,86,"Lvl");
gadOutp := is.CreatePropGadget(OL,147,29,6,40,0,128,SYS.ADR(knobOutp),I.gadgHNone,is.stdAct+{I.followMouse},pfV);
AddGad(gadOutp);
Print(rp,138,76,"Outp");
Print(rp,138,86,"Lvl");
gadFreq := is.CreateStrGadget(FR,166,40,48,8,6,"","",NIL,is.stdGad,is.stdAct+{I.stringRight});
Box(rp,165,39,50,10,FALSE,0);
AddGad(gadFreq);
Print(rp,166,35,"Freq");
gadOM := is.CreateBoolGadget(OM,177,65,25,12,"",NIL,NIL,is.stdGad,is.stdAct);
Box(rp,177,65,25,12,TRUE,-1);
AddGad(gadOM);
Print(rp,178,61,"Mode");
(*----------- Algorithm ----------*)
Box(rp,8,94,124,90,FALSE,-1);
Print(rp,13,102,"Algorithm");
Print(rp,26,128,"1 2 3 4 5 6"); Print(rp,26,160,"1 2 3 4 5 6");
FOR i := 1 TO 6 DO
Box(rp,i*16+8,120,12,12,TRUE,-1);
gadAlgM[i] := is.CreateBoolGadget(M1-1+i,i*16+8,120,12,12,"",NIL,NIL,is.stdGad,is.stdAct);
AddGad(gadAlgM[i]);
Box(rp,i*16+8,152,12,12,TRUE,-1);
gadAlgC[i] := is.CreateBoolGadget(C1-1+i,i*16+8,152,12,12,"",NIL,NIL,is.stdGad,is.stdAct);
AddGad(gadAlgC[i]);
END;
Print(rp,26,115,"Modulator"); Print(rp,26,175,"Carrier");
(*------------- LFO -------------*)
Box(rp,228,5,84,85,FALSE,-1);
Print(rp,233,13,"LFO");
gadLFOs := is.CreatePropGadget(SP,265,47,40,6,128,0,SYS.ADR(knobLFOs),I.gadgHNone,is.stdAct,pfH);
gadLFOd := is.CreatePropGadget(DE,265,57,40,6,128,0,SYS.ADR(knobLFOd),I.gadgHNone,is.stdAct,pfH);
gadLFOa := is.CreatePropGadget(AM,265,67,40,6,128,0,SYS.ADR(knobLFOa),I.gadgHNone,is.stdAct,pfH);
gadLFOp := is.CreatePropGadget(PM,265,77,40,6,128,0,SYS.ADR(knobLFOp),I.gadgHNone,is.stdAct,pfH);
Print(rp,235,52,"Spd"); Print(rp,235,62,"Del");
Print(rp,235,72,"AMD"); Print(rp,235,82,"PMD");
gadLFOw := is.CreateBoolGadget(WA,277,24,25,12,"",NIL,NIL,is.stdGad,is.stdAct);
Box(rp,277,24,25,12,TRUE,-1);
Print(rp,235,32,"Wave");
AddGad(gadLFOs); AddGad(gadLFOd);
AddGad(gadLFOa); AddGad(gadLFOp);
AddGad(gadLFOw);
(*------------ Sound ------------*)
Box(rp,138,94,174,90,FALSE,-1);
Print(rp,143,102,"Sound");
gadCalc := is.CreateBoolGadget(CS,153,109,38,14,"",NIL,NIL,is.stdGad,is.stdAct);
Box(rp,153,109,38,14,TRUE,-1);
Print(rp,153+3,110+8,"Calc");
gadLen := is.CreateStrGadget(LN,148,140,48+8,8,7,"","",NIL,is.stdGad,is.stdAct+{I.longint,I.stringRight});
Box(rp,148-1,140-1,48+8+2,8+2,FALSE,0);
Print(rp,148,135,"Size");
gadTsp := is.CreateStrGadget(TP,148,165,48,8,6,"","",NIL,is.stdGad,is.stdAct+{I.stringRight});
Box(rp,147,165-1,48+2,8+2,FALSE,0);
Print(rp,148,160,"Transp");
gadFeed := is.CreateStrGadget(FB,280,100,16,8,2,"","",NIL,is.stdGad,is.stdAct+{I.longint,I.stringRight});
Box(rp,280-1,100-1,16+2,8+2,FALSE,0);
Print(rp,210,100+6,"Feedback");
gadPer := is.CreateStrGadget(PR,264,115,32,8,4,"","",NIL,is.stdGad,is.stdAct+{I.longint,I.stringRight});
Box(rp,264-1,115-1,32+2,8+2,FALSE,0);
Print(rp,210,115+6,"Period");
gadMode := is.CreateBoolGadget(MD,268,130,25,12,"",NIL,NIL,is.stdGad,is.stdAct);
Box(rp,268,130,25,12,TRUE,-1);
Print(rp,210,130+8,"Mode");
gadFlt := is.CreateBoolGadget(FL,268,145,25,12,"",NIL,NIL,is.stdGad,is.stdAct);
Box(rp,268,145,25,12,TRUE,-1);
Print(rp,210,145+8,"Filter");
gadRel := is.CreatePropGadget(RR,264,165,40,6,128,0,SYS.ADR(knobRel),I.gadgHNone,is.stdAct,pfH);
AddGad(gadRel);
Print(rp,210,165+5,"RlRate");
AddGad(gadLen);
AddGad(gadCalc);
AddGad(gadTsp);
AddGad(gadFeed);
AddGad(gadPer);
AddGad(gadMode);
AddGad(gadFlt);
(*-------------------------------*)
I.RefreshGadgets(gadOp[1],win,NIL);
IF pal THEN DrawKeyboard END;
END SetUpScreen;
(*------------------------------------------------------------------------*)
PROCEDURE DrawKeyboard;
CONST X=20; Y=204; H1=26; H2=15; N=5*7;
VAR i: INTEGER;
BEGIN
Box(rp,0,190,320,55,TRUE,1);
Box(rp,8,195,304,45,FALSE,-1);
i := 0; WHILE i <= N DO
g.SetAPen(rp,2);
g.Move(rp,X+i*8,Y);
g.Draw(rp,X+i*8,Y+H1);
IF i < N THEN
g.SetAPen(rp,3);
g.RectFill(rp,X+1+i*8,Y,X+7+i*8,Y+H1);
END;
IF (i # 0) & (ABS((i-1) MOD 7-4) # 2) THEN
g.SetAPen(rp,0);
g.RectFill(rp,X-2+i*8,Y,X-2+4+i*8,Y+H2);
END;
INC(i) END;
g.SetAPen(rp,2);
g.Move(rp,X,Y); g.Draw(rp,X+280,Y);
g.Move(rp,X,Y+H1); g.Draw(rp,X+280,Y+H1);
END DrawKeyboard;
(*------------------------------------------------------------------------*)
PROCEDURE MarkKey(nr: INTEGER; mark: BOOLEAN);
TYPE
Tab=ARRAY 12 OF INTEGER;
CONST
tab=Tab(0,4,8,12,16,24,28,32,36,40,44,48);
VAR
x,y: INTEGER;
black: BOOLEAN;
nrDIV12,nrMOD12: INTEGER;
BEGIN
(* $OvflChk- $RangeChk- $NilChk- *)
IF (~pal) OR (nr < 0) OR (nr > 59) THEN RETURN END;
SYS.SETREG(7,nr DIV 12);
nrDIV12 := SHORT(SYS.REG(7));
nrMOD12 := SHORT(SYS.ROT(SYS.REG(7),-16));
black := nrMOD12 IN {1,3,6,8,10};
x := 23 + nrDIV12 * 56 + tab[nrMOD12];
IF black THEN y := 215 ELSE y := 225 END;
IF black # mark THEN g.SetAPen(rp,0) ELSE g.SetAPen(rp,3) END;
g.RectFill(rp,x,y,x+2,y+2);
(* $OvflChk= $RangeChk= $NilChk= *)
END MarkKey;
(*------------------------------------------------------------------------*)
PROCEDURE CheckLine(m,c: SHORTINT);
VAR
i: INTEGER;
found: BOOLEAN;
BEGIN
IF m <= c THEN RETURN END;
found := FALSE;
i := 1;
WHILE (i <= algo.numLines) & ~ found DO
IF (algo.line[i-1].mod=m) & (algo.line[i-1].car=c) THEN
found := TRUE
ELSE
INC(i)
END
END;
IF found THEN
WHILE i<algo.numLines DO
algo.line[i-1].mod := algo.line[i].mod;
algo.line[i-1].car := algo.line[i].car;
INC(i)
END;
DEC(algo.numLines)
ELSE
INC(algo.numLines);
algo.line[i-1].mod := m;
algo.line[i-1].car := c;
END
END CheckLine;
(*------------------------------------------------------------------------*)
PROCEDURE GetCarrier;
VAR c,i : INTEGER;
mods : BOOLEAN;
BEGIN
output := 0;
maxoutp := 0;
FOR c := 0 TO 5 DO
mods := FALSE;
FOR i := 1 TO algo.numLines DO
IF algo.line[i-1].mod = c THEN mods := TRUE END;
END;
isCarrier[c] := ~ mods;
END;
g.SetAPen(rp,1); g.RectFill(rp,24,164,115,168);
g.SetAPen(rp,3);
FOR c := 0 TO 5 DO
IF isCarrier[c] THEN
g.Move(rp,c*16+30,164);
g.Draw(rp,c*16+30,167);
INC(output,op[c].outp);
IF op[c].outp > maxoutp THEN maxoutp := op[c].outp END;
END;
END;
END GetCarrier;
(*------------------------------------------------------------------------*)
PROCEDURE DrawAlgo;
VAR i : INTEGER;
BEGIN
g.SetAPen(rp,1); g.RectFill(rp,24,132,115,151);
g.SetAPen(rp,3);
FOR i := 1 TO algo.numLines DO
g.Move(rp,algo.line[i-1].mod*16+30,132);
g.Draw(rp,algo.line[i-1].car*16+30,151);
END;
GetCarrier;
IF feedback # 0 THEN
g.Move(rp,5*16+30,132);
g.Draw(rp,5*16+30,151);
END;
END DrawAlgo;
(*------------------------------------------------------------------------*)
PROCEDURE NextLFOWave;
VAR i,j : INTEGER;
adr : UNTRACED POINTER TO SYS.BYTE;
BEGIN
IF lfo.wave=sqr THEN lfo.wave:=sin ELSE INC(lfo.wave) END;
FOR i:=0 TO 255 DO
CASE lfo.wave OF
| sin:
lfoTab[i] := -sinTab[i*32];
| tri:
CASE i DIV 64 OF
| 0: lfoTab[i] := SHORT(i*2);
|1,2: lfoTab[i] := SHORT(255-i*2);
| 3: lfoTab[i] := SHORT(i*2-512);
END;
| down:
lfoTab[i] := SHORT(i-128);
| up:
lfoTab[i] := SHORT(127-i);
| sqr:
lfoTab[i] := SHORT((i DIV 128) * 255 - 128);
END;
END;
adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,LFOPics) + LONG(LONG(lfo.wave)) * 16);
e.CopyMem(adr^,lfoPic^,16);
I.DrawImage(rp,lfoImg^,gadLFOw.leftEdge+5,gadLFOw.topEdge+2)
END NextLFOWave;
(*------------------------------------------------------------------------*)
PROCEDURE BufLen(nr:INTEGER): LONGINT; (* 1 <= nr <= 5 *)
BEGIN
RETURN SYS.LSH(lenHi,5-nr);
END BufLen;
(*------------------------------------------------------------------------*)
PROCEDURE Buffer(nr:INTEGER): SYS.ADDRESS; (* 1 <= nr <= 5 *)
TYPE A = ARRAY 5 OF LONGINT;
CONST tab = A(0,16,24,28,30);
BEGIN
RETURN SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,soundBuf) + tab[nr-1]*lenHi);
END Buffer;
(*------------------------------------------------------------------------*)
PROCEDURE LoopsOff;
BEGIN
oneShotHi := lenHi;
repeatHi := 0;
END LoopsOff;
(*------------------------------------------------------------------------*)
PROCEDURE AllocMem(VAR buf: SYS.ADDRESS; size: LONGINT; chip: BOOLEAN);
VAR oldReqs : LONGSET;
BEGIN
oldReqs := ol.MemReqs;
ol.MemReqs := LONGSET{e.memClear};
IF chip THEN INCL(ol.MemReqs,e.chip) END;
ol.Allocate(buf,size);
ol.MemReqs := oldReqs;
END AllocMem;
(*------------------------------------------------------------------------*)
PROCEDURE GetMem;
VAR i : INTEGER;
str : UNTRACED POINTER TO ARRAY 7 OF CHAR;
err : BOOLEAN;
n : SHORTINT;
BEGIN
IF soundLen > 253952 THEN soundLen := 253952 END;
lenHi := soundLen DIV 31;
IF ODD(lenHi) THEN DEC(lenHi) END;
IF lenHi<4 THEN lenHi := 4 END;
soundLen := lenHi * 31;
str := is.GadgetText(gadLen);
n := 6;
IF soundLen<100000 THEN DEC(n) END;
IF soundLen< 10000 THEN DEC(n) END;
IF soundLen< 1000 THEN DEC(n) END;
err := c.IntToStr(soundLen,str^,10,n," ");
I.RefreshGList(gadLen,win,NIL,1);
IF soundBuf # NIL THEN ol.Dispose(soundBuf) END;
AllocMem(soundBuf,soundLen,TRUE);
IF soundBuf=NIL THEN
soundLen:=0;
IF Request("No mem for buffer","","Cancel") THEN END;
END;
END GetMem;
(*------------------------------------------------------------------------*)
PROCEDURE InitOp(nr: INTEGER);
BEGIN
op[nr].scR := 64;
op[nr].scL := 64;
op[nr].r[0] := 127;
op[nr].r[1] := 0;
op[nr].r[2] := 0;
op[nr].r[3] := 0;
op[nr].l[0] := 127;
op[nr].l[1] := 0;
op[nr].l[2] := 0;
op[nr].l[3] := 0;
op[nr].outp := 0;
op[nr].freq := 1.0;
op[nr].mode := ratio;
END InitOp;
(*------------------------------------------------------------------------*)
PROCEDURE SetREALGad(gad:I.GadgetPtr; x:REAL);
VAR str : UNTRACED POINTER TO ARRAY 6 OF CHAR;
v,n : INTEGER;
BEGIN
str := is.GadgetText(gad);
IF RealToString(x,str^,4) THEN END;
str^[5] := 0X;
I.RefreshGList(gad,win,NIL,1);
END SetREALGad;
(*------------------------------------------------------------------------*)
PROCEDURE GetREALGad(gad:I.GadgetPtr; VAR x:REAL);
VAR err: BOOLEAN;
str: UNTRACED POINTER TO ARRAY 6 OF CHAR;
BEGIN
str := is.GadgetText(gad);
IF ~ StringToReal(str^,x) THEN x := 1.0 END;
x := ABS(x);
END GetREALGad;
(*------------------------------------------------------------------------*)
PROCEDURE ShowPot(rp:g.RastPortPtr; gad: I.GadgetPtr);
VAR val : INTEGER;
BEGIN
val := 127-is.VertPot(gad,128);
PrintNumber(rp,gad.leftEdge+4,gad.topEdge-6,val);
END ShowPot;
(*------------------------------------------------------------------------*)
PROCEDURE SetOp(nr: INTEGER);
VAR
i: INTEGER;
adr: UNTRACED POINTER TO SYS.BYTE;
gad: I.GadgetPtr;
BEGIN
adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,MixPics) + LONG(LONG(op[nr].mode)) * 12);
e.CopyMem(adr^,mixPic^,12);
I.DrawImage(rp,mixImg^,gadOM.leftEdge+5,gadOM.topEdge+3);
FOR i := 1 TO 6 DO
IF i=nr+1 THEN g.SetAPen(rp,3) ELSE g.SetAPen(rp,1) END;
Frame(rp,i*16+81,7,14,14);
Frame(rp,i*16+80,7,16,15);
END;
FOR i := 0 TO 3 DO
gad := gadEG[i];
is.SetProp(gad,win,NIL,0,127-op[nr].r[i],0,128);
ShowPot(rp,gad);
gad :=gadEG[4+i];
is.SetProp(gad,win,NIL,0,127-op[nr].l[i],0,128);
ShowPot(rp,gad);
END;
is.SetProp(gadScL, win,NIL,0,127-op[nr].scL ,0,128);
is.SetProp(gadScR, win,NIL,0,127-op[nr].scR ,0,128);
is.SetProp(gadOutp,win,NIL,0,127-op[nr].outp,0,128);
ShowPot(rp,gadScL);
ShowPot(rp,gadScR);
ShowPot(rp,gadOutp);
SetREALGad(gadFreq,op[nr].freq);
END SetOp;
(*------------------------------------------------------------------------*)
PROCEDURE SetLFO;
BEGIN
is.SetProp(gadLFOs,win,NIL,lfo.spd,0,128,0);
is.SetProp(gadLFOd,win,NIL,lfo.del,0,128,0);
is.SetProp(gadLFOa,win,NIL,lfo.amd,0,128,0);
is.SetProp(gadLFOp,win,NIL,lfo.pmd,0,128,0);
lfoInc := (LONG(lfo.spd)+1) * 64;
IF lfo.wave=sin THEN lfo.wave:=sqr ELSE DEC(lfo.wave) END;
NextLFOWave;
END SetLFO;
(*------------------------------------------------------------------------*)
PROCEDURE SetRR;
BEGIN
is.SetProp(gadRel,win,NIL,127-rRate,0,128,0);
deltaVol:=(trans.Exp(0.05*rRate)-1.0)*0.112;
END SetRR;
(*------------------------------------------------------------------------*)
PROCEDURE SetFeedback;
VAR str: UNTRACED POINTER TO ARRAY 2 OF CHAR;
BEGIN
IF feedback<0 THEN feedback:=0 END;
IF feedback>7 THEN feedback:=7 END;
str := is.GadgetText(gadFeed);
str^[0] := CHR(feedback+ORD("0"));
str^[1] := 0X;
I.RefreshGList(gadFeed,win,NIL,1);
DrawAlgo;
END SetFeedback;
(*------------------------------------------------------------------------*)
PROCEDURE SetFilter;
VAR adr: UNTRACED POINTER TO SYS.BYTE;
BEGIN
as.Filter(filter);
adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,MixPics) + 4 * 12);
IF ~filter THEN adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,adr)+12) END;
e.CopyMem(adr^,mixPic^,12);
I.DrawImage(rp,mixImg^,gadFlt.leftEdge+5,gadFlt.topEdge+3)
END SetFilter;
(*------------------------------------------------------------------------*)
PROCEDURE SetMode;
VAR adr: UNTRACED POINTER TO SYS.BYTE;
BEGIN
adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,MixPics) + 2 * 12);
IF mode=poly THEN adr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,adr)+12) END;
e.CopyMem(adr^,mixPic^,12);
I.DrawImage(rp,mixImg^,gadMode.leftEdge+5,gadMode.topEdge+3)
END SetMode;
(*------------------------------------------------------------------------*)
PROCEDURE SetKeys;
VAR i:INTEGER;
BEGIN
FOR i:=0 TO 127 DO key[i]:=-1 END;
key[49]:=0; key[33]:=1; key[50]:=2; key[34]:=3; key[51]:=4;
key[52]:=5; key[36]:=6; key[53]:=7; key[37]:=8; key[54]:=9; key[38]:=10;
key[55]:=11;key[56]:=12;key[40]:=13;key[57]:=14;key[41]:=15;key[58]:=16;
key[97]:=17;key[43]:=18;
key[66]:=11;key[16]:=12;key[2] :=13;key[17]:=14;key[3]:=15; key[18]:=16;
key[19]:=17;key[5] :=18;key[20]:=19;key[6] :=20;key[21]:=21;key[7] :=22;
key[22]:=23;key[23]:=24;key[9] :=25;key[24]:=26;key[10]:=27;key[25]:=28;
key[26]:=29;key[12]:=30;key[27]:=31;key[13]:=32;key[68]:=33;key[65]:=34;
key[0] :=10;
END SetKeys;
(*------------------------------------------------------------------------*)
PROCEDURE SetPer;
VAR i : INTEGER;
p : REAL;
str : UNTRACED POINTER TO ARRAY 4 OF CHAR;
err : BOOLEAN;
n : SHORTINT;
BEGIN
IF Per < 124 THEN Per := 124 END;
IF Per > 999 THEN Per := 999 END;
str := is.GadgetText(gadPer);
err := c.IntToStr(Per,str^,10,3," ");
I.RefreshGList(gadPer,win,NIL,1);
FOR i := 35 TO 0 BY -1 DO
IF i MOD 12 = 11 THEN p := Per ELSE p := p * 1.059463094 END;
period[i] := p;
END;
END SetPer;
(*------------------------------------------------------------------------*)
PROCEDURE Muls (i{0},j{1}: INTEGER): LONGINT; (* $EntryExitCode- *)
BEGIN
SYS.INLINE(0C1C1H,04E75H); (* MULS D1,D0 ; RTS *)
END Muls;
(*---------------------------------------------------------------------*)
PROCEDURE Inc(freq,faktor:REAL; okt:INTEGER; mode:SHORTINT): LONGINT;
BEGIN
(* $OvflChk- $RangeChk- *)
IF mode=ratio THEN
RETURN SYS.LSH(ENTIER(freq * faktor * transp * (65536.0*64.0) + 0.5),okt)
ELSE (* mode=fixed *)
RETURN ENTIER(freq*(0.738184*65536.0));
END;
(* $OvflChk= $RangeChk= *)
END Inc;
(*------------------------------------------------------------------------*)
PROCEDURE CalcSound();
VAR
i,j : INTEGER;
b,k : INTEGER;
arg : ARRAY 6 OF LONGINT;
inc : ARRAY 6 OF LONGINT;
d : ARRAY 6 OF INTEGER;
a : ARRAY 6 OF LONGINT;
l : LONGINT;
y : SHORTINT;
mod : ARRAY 6,8 OF SHORTINT;
num : ARRAY 6 OF SHORTINT;
phi : INTEGER;
m,c : SHORTINT;
ra : ARRAY 6,4 OF LONGINT;
le : ARRAY 6,4 OF LONGINT;
raTemp : LONGINT;
leTemp : LONGINT;
e : ARRAY 6 OF LONGINT;
p : ARRAY 6 OF SHORTINT;
outp : ARRAY 6 OF INTEGER;
buf : INTEGER;
bufs2Calc : INTEGER;
part : INTEGER;
parts2Calc : INTEGER;
bufLen : LONGINT;
bufPtr : UNTRACED POINTER TO SHORTINT;
bufPtr2 : UNTRACED POINTER TO SHORTINT;
rate : REAL;
raSc : REAL;
leSc : REAL;
mlevel : INTEGER;
fast : BOOLEAN;
BEGIN
(* $OvflChk- $RangeChk- $NilChk- *)
GetCarrier;
IF output = 0 THEN
IF ~autoCalc THEN
IF Request("No output level","","Cancel") THEN END;
RETURN
END;
END;
IF soundBuf = NIL THEN
IF ~autoCalc & Request("No buffer","","Cancel") THEN END;
RETURN
END;
SetTimer(FALSE);
ip.Busy(win);
LockWindow(win);
IF output=0 THEN
mlevel := 0;
ELSE
IF chord=0 THEN mlevel := 2080;
ELSE mlevel := 680; END;
mlevel := SHORT(ENTIER((mlevel / output) * maxoutp))
END;
FOR i := 0 TO 5 DO num[i] := -1 END;
FOR i := 0 TO algo.numLines-1 DO
m := algo.line[i].mod; c := algo.line[i].car;
INC(num[c]); mod[c,num[c]] := m;
END;
fast := TRUE;
FOR i := 0 TO 5 DO
IF (op[i].outp#0)&((op[i].scR#64)OR(op[i].scL#64)OR(op[i].mode=fixed))
THEN fast := FALSE
END;
END;
IF fast THEN bufs2Calc := 1 ELSE bufs2Calc := 5 END;
IF chord=0 THEN parts2Calc := 1 ELSE parts2Calc := 3 END;
FOR buf := 1 TO bufs2Calc DO
FOR i := 0 TO 5 DO
raSc := trans.Pow(buf - 1, op[i].scR / 64 + 1);
FOR j := 0 TO 3 DO
le[i,j] := LONG(LONG(op[i].l[j])) * (128 * 65536);
rate := (trans.Exp(0.08*op[i].r[j])-1) * 41218 * raSc;
IF rate < 1.065353E+9 THEN ra[i,j] := ffp.Fix(rate);
ELSE ra[i,j] := 1065353216; END;
IF (j>0) & (op[i].l[j]<op[i].l[j-1]) THEN ra[i,j] := -ra[i,j] END;
END;
leSc := op[i].scL - 64;
IF leSc >= 0 THEN leSc := 1 - leSc * (5-buf) / 256;
ELSE leSc := 1 + leSc * (buf-1) / 256 END;
outp[i] := SHORT(ffp.Fix(op[i].outp * leSc * 8 + 0.5));
END;
FOR part := 0 TO parts2Calc-1 DO
FOR i := 0 TO 5 DO
arg[i] := 0; p[i] := 0; e[i] := 0;
inc[i] := Inc(op[i].freq,chordTable[chord,part],buf,op[i].mode);
END;
k := 0;
bufPtr := Buffer(buf);
bufLen := BufLen(buf);
FOR l := 0 TO bufLen-1 DO
IF k=0 THEN
FOR i := 0 TO 5 DO
raTemp := ra[i,p[i]]; leTemp := le[i,p[i]];
INC(e[i],raTemp);
IF raTemp < 0 THEN
IF e[i] <= leTemp THEN
e[i] := leTemp;
IF p[i] < 3 THEN INC(p[i]) END;
END;
ELSIF raTemp > 0 THEN
IF e[i] >= leTemp THEN
e[i] := leTemp;
IF p[i] < 3 THEN INC(p[i]) END;
END;
END;
a[i] := Muls(SHORT(SYS.ROT(e[i],-16)),outp[i]);
END;
END;
k := (k+1) MOD 16;
b := 0;
d[5] := 0;
IF SHORT(SYS.ROT(a[5],-16))=0 THEN
d[5] := 0
ELSE
i := feedback+1; REPEAT
phi := SHORT(SYS.ROT(arg[5],-16)) + d[5];
d[5] := SHORT(ASH(Muls(SHORT(SYS.ROT(a[5],-16)),LONG(sinTab[phi MOD 8192])),-3));
DEC(i) UNTIL i=0;
IF isCarrier[5] THEN INC(b,d[5]) END;
END;
INC(arg[5],inc[5]);
i:=4; REPEAT
IF SHORT(SYS.ROT(a[i],-16))=0 THEN
d[i] := 0
ELSE
phi := SHORT(SYS.ROT(arg[i],-16));
FOR j:=0 TO num[i] DO
INC(phi,d[mod[i,j]])
END;
d[i] := SHORT(ASH(Muls(SHORT(SYS.ROT(a[i],-16)),LONG(sinTab[phi MOD 8192])),-3));
IF isCarrier[i] THEN INC(b,d[i]) END;
END;
INC(arg[i],inc[i]);
DEC(i) UNTIL i<0;
y := SHORT(SHORT(SYS.ROT(Muls(b,mlevel),-16)));
IF part=0 THEN bufPtr^ := y;
ELSE INC(bufPtr^,y) END;
bufPtr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,bufPtr)+1);
END; (* FOR l *)
END; (* FOR part *)
END; (* FOR buf *)
IF fast THEN
FOR buf := 2 TO 5 DO
bufPtr := Buffer(buf);
bufPtr2 := Buffer(buf-1);
bufLen := BufLen(buf);
FOR l:=0 TO bufLen-1 DO
bufPtr^ := bufPtr2^;
bufPtr := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,bufPtr) +1);
bufPtr2 := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,bufPtr2)+2);
END;
END;
END;
SetTimer(TRUE);
UnLockWindow(win);
ip.Normal(win);
disabled := TRUE;
as.PlaySound(3,SYS.ADR(beep),4,500,40,100);
state[3] := end;
disabled := FALSE;
(* $OvflChk= $RangeChk= $NilChk= *)
END CalcSound;
(*------------------------------------------------------------------------*)
PROCEDURE SetLoop;
VAR
rp : g.RastPortPtr;
mes : I.IntuiMessage;
offs : LONGINT;
last : LONGINT;
pip : I.PropInfoPtr;
mark1 : LONGINT;
mark2 : LONGINT;
mx : INTEGER;
i,id : INTEGER;
sGad : I.GadgetPtr;
nr : INTEGER;
(*···············································*)
PROCEDURE Plot;
VAR i,j : INTEGER;
buf : UNTRACED POINTER TO SHORTINT;
x : LONGINT;
y : INTEGER;
str : ARRAY 6 OF CHAR;
err : BOOLEAN;
m : LONGINT;
BEGIN
g.SetAPen(rp,1); g.RectFill(rp,6,26,313,93);
g.RectFill(rp,122,12,208,22);
IF (mark1 # 0) OR (mark2 # 0) THEN
m := SYS.LSH(mark1,5-nr);
x := (m-offs);
buf:=Buffer(nr);
buf:=SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,buf)+m);
y:=buf^;
err:=c.IntToStr(y,str,10,4," ");
Print(rp,122,20,str);
y := y DIV 4;
g.SetAPen(rp,2); g.Move(rp,6,59-y); g.Draw(rp,313,59-y);
IF (x>=0)&(x<=307) THEN g.Move(rp,SHORT(6+x),26);g.Draw(rp,SHORT(6+x),93) END;
m := SYS.LSH(mark2,5-nr);
x := (m-offs);
buf:=Buffer(nr);
buf:=SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,buf)+m);
y:=buf^;
err := c.IntToStr(y,str,10,4," ");
Print(rp,176,20,str);
y := y DIV 4;
g.SetAPen(rp,0); g.Move(rp,6,59-y); g.Draw(rp,313,59-y);
IF (x>=0)&(x<=307) THEN g.Move(rp,SHORT(6+x),26);g.Draw(rp,SHORT(6+x),93) END;
END;
buf := Buffer(nr);
buf:=SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,buf)+offs);
g.SetAPen(rp,3);
i:=0;WHILE i<=307 DO
IF i < BufLen(nr) THEN
j := 59 - LONG(buf^) DIV 4;
IF i=0 THEN g.Move(rp,i+6,j) ELSE g.Draw(rp,i+6,j) END;
buf:=SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,buf)+1);
END;
INC(i)
END;
END Plot;
(*···············································*)
PROCEDURE GetLoop;
BEGIN
mark1:=oneShotHi;
mark2:=mark1+repeatHi;
IF mark1=lenHi THEN mark1:=0;mark2:=0 END;
END GetLoop;
(*···············································*)
PROCEDURE SetLoop;
VAR i : INTEGER;
BEGIN
IF mark1 >= lenHi THEN mark1:=lenHi-2 END;
IF mark2 >= lenHi THEN mark2:=lenHi-2 END;
IF (mark1=0) & (mark2=0) THEN
oneShotHi := lenHi; repeatHi := 0;
RETURN
END;
IF mark1<mark2 THEN oneShotHi:=mark1 ELSE oneShotHi:=mark2 END;
repeatHi := ABS(mark1-mark2);
END SetLoop;
(*···············································*)
PROCEDURE SetBuf;
VAR hBody : LONGINT;
i : INTEGER;
BEGIN
offs := 0;
IF BufLen(nr) < 600 THEN
hBody := 65535
ELSE
hBody := 19000000 DIV (BufLen(nr)-308);
END;
I.NewModifyProp(gadOffs^,win2,NIL,pfH,0,0,hBody,0,1);
i := 1; WHILE i <= 5 DO
IF i=nr THEN g.SetAPen(rp,3) ELSE g.SetAPen(rp,1) END;
Frame(rp,i*16+49,107,14,14);
Frame(rp,i*16+48,107,16,15);
INC(i) END
END SetBuf;
(*···············································*)
BEGIN (* SetLoop *)
IF soundBuf=NIL THEN
IF Request("No buffer","","Cancel") THEN END;
RETURN;
END;
win2 := is.CreateWindow("Set Loop",0,50,320,126,scr,
LONGSET{I.activate,I.windowClose,I.windowDrag,I.windowDepth,I.rmbTrap},
LONGSET{I.gadgetUp,I.gadgetDown,I.closeWindow,I.mouseButtons},NIL);
ip.Normal(win2);
LockWindow(win);
ip.Busy(win);
rp := win2.rPort;
Box(rp,0,11,320,115,TRUE,1); Box(rp,5,25,310,70,FALSE,-1);
IF gadClr=NIL THEN gadClr:=is.CreateBoolGadget(CL,256,108,46,12,"",NIL,NIL,is.stdGad,is.stdAct) END;
Box(rp,256,108,46,12,TRUE,-1);
Print(rp,259,116,"Clear");
is.AddGadget(win2,gadClr);
Print(rp,220,116,"Loop");
FOR i:=1 TO 5 DO
IF gadBuf[i]=NIL THEN gadBuf[i]:=is.CreateBoolGadget(B1+i-1,50+i*16,108,12,12,"",NIL,NIL,is.stdGad,is.stdAct) END;
Box(rp,50+i*16,108,12,12,TRUE,-1);
is.AddGadget(win2,gadBuf[i]);
END;
Print(rp,12,116,"Octave");
Print(rp,68,116,"1 2 3 4 5");
IF gadOffs=NIL THEN gadOffs:=is.CreatePropGadget(OS,10,98,300,6,0,0,SYS.ADR(knobPlot),I.gadgHNone,is.stdAct,pfH) END;
is.AddGadget(win2,gadOffs);
I.RefreshGadgets(gadClr,win2,NIL);
pip := gadOffs^.specialInfo;
nr:=1;
SetBuf;
GetLoop;
Plot;
LOOP
is.GetIMsg(win2,mes,TRUE);
IF I.gadgetUp IN mes.class THEN
sGad := mes.iAddress; id := sGad^.gadgetID;
CASE id OF
| B1..B5 : nr:=id-B1+1; GetLoop; SetBuf; Plot;
| CL : mark1:=0; mark2:=0; SetLoop; Plot;
ELSE
END
END;
IF I.closeWindow IN mes.class THEN EXIT END;
IF I.mouseButtons IN mes.class THEN
mx := mes.mouseX-6;
IF (mx>=0)&(mx<=307)&(mes.mouseY<95) THEN
CASE mes.code OF
I.selectDown: mark1:=2*SYS.LSH(offs+mx,nr-6); SetLoop; Plot|
I.menuDown : mark2:=2*SYS.LSH(offs+mx,nr-6); SetLoop; Plot
ELSE
END;
END;
END;
IF (I.gadgetDown IN mes.class) & (mes.iAddress=gadOffs) THEN
LOOP
is.GetIMsg(win2,mes,FALSE);
last:=offs;
offs := ENTIER(I.UIntToLong(pip^.horizPot)/65535.0 * (BufLen(nr)-308));
IF offs > BufLen(nr)-308 THEN offs := BufLen(nr)-308 END;
IF offs < 0 THEN offs := 0 END;
IF offs#last THEN Plot END;
IF I.gadgetUp IN mes.class THEN EXIT END;
d.Delay(5);
END
END
END;
UnLockWindow(win);
ip.Normal(win);
is.DeleteWindow(win2); win2:=NIL
END SetLoop;
(*------------------------------------------------------------------------*)
PROCEDURE FourierAnalysis;
VAR
rp : g.RastPortPtr;
mes : I.IntuiMessage;
buf : UNTRACED POINTER TO ARRAY 50000 OF SHORTINT;
f : ARRAY 64 OF REAL;
max : REAL;
i,k,inc,argA,argB,wert,h : INTEGER;
a,b,bufArg,bufInc : LONGINT;
BEGIN
(* $RangeChk- $OvflChk- $NilChk- *)
IF soundBuf=NIL THEN
IF Request("No buffer","","Cancel") THEN END;
RETURN;
END;
IF repeatHi=0 THEN
IF Request("No loop","","Cancel") THEN END;
RETURN;
END;
win2 := is.CreateWindow("Fourier-Analysis",20,50,280,116,scr,
LONGSET{I.activate,I.windowClose,I.windowDrag,I.windowDepth},
LONGSET{I.closeWindow},NIL);
ip.Normal(win2);
ip.Busy(win);
LockWindow(win);
rp := win2.rPort;
Box(rp,0,11,280,105,TRUE,1); Box(rp,5,15,270,95,FALSE,-1);
g.SetAPen(rp,2);
buf := SYS.VAL(SYS.ADDRESS,SYS.VAL(LONGINT,soundBuf) + oneShotHi * 16);
bufInc := repeatHi * 16 * 65536 DIV 128;
inc := 64;
max := 0;
k := 1; WHILE k < 64 DO
argA := 0;
argB := 2048;
bufArg := 0;
a := 0; b := 0;
i := 0; WHILE i < 128 DO
wert := buf[SHORT(SYS.ROT(bufArg,-16))];
INC(a,wert * sinTab[argA MOD 8192]);
INC(b,wert * sinTab[argB MOD 8192]);
INC(argA,inc);
INC(argB,inc);
INC(bufArg,bufInc);
INC(i) END;
f[k] := trans.Sqrt(a*1.0*a + b*1.0*b);
IF f[k] > max THEN max := f[k] END;
INC(inc,64);
INC(k) END;
IF max <= 1.0E-8 THEN max := 1 END;
k := 1; WHILE k < 64 DO
h := SHORT(ffp.Fix(f[k] / max * 80.0 + 0.5));
IF h <= 0 THEN h := 1 END;
g.RectFill(rp,10+k*4,102-(h-1),10+2+k*4,102);
INC(k) END;
is.GetIMsg(win2,mes,TRUE);
UnLockWindow(win);
ip.Normal(win);
is.DeleteWindow(win2); win2:=NIL;
(* $RangeChk= $OvflChk= $NilChk= *)
END FourierAnalysis;
(*------------------------------------------------------------------------*)
PROCEDURE SetLine(l,m,c: INTEGER);
BEGIN
algo.line[l-1].mod:=SHORT(m-1);
algo.line[l-1].car:=SHORT(c-1);
END SetLine;
(*------------------------------------------------------------------------*)
PROCEDURE Refresh;
BEGIN
SetOp(0);
SetREALGad(gadTsp,transp);
SetLFO;
SetRR;
SetFeedback;
SetFilter;
SetMode;
SetPer;
GetMem;
END Refresh;
(*------------------------------------------------------------------------*)
PROCEDURE SetName(name: ARRAY OF CHAR); (* $CopyArrays- *)
VAR voicename: e.STRING;
i: LONGINT;
BEGIN
COPY(name,voicename);
FOR i := str.Length(voicename)-1 TO 0 BY -1 DO
CASE voicename[i] OF ".": voicename[i] := 0X | ":","/": str.Delete(voicename,0,i+1); i := -1 ELSE END;
END;
WHILE str.Length(voicename) < 16 DO str.AppendChar(voicename," ") END;
e.CopyMem(voicename,scrtitle[21],16);
I.SetWindowTitles(win,-1,SYS.ADR(scrtitle));
END SetName;
(*------------------------------------------------------------------------*)
PROCEDURE Save8SVX(filePath:ARRAY OF CHAR): BOOLEAN; (* $CopyArrays- *)
TYPE
Voice8Header = STRUCT
oneShotHiSamples : LONGINT;
repeatHiSamples : LONGINT;
samplesPerHiCycle : LONGINT;
samplesPerSec : INTEGER;
ctOctave,sCompression : SHORTINT;
volume : STRUCT hi,lo: INTEGER END;
END;
VAR
vhdr : Voice8Header;
bodySize : LONGINT;
ok : BOOLEAN;
i : INTEGER;
size : LONGINT;
len : LONGINT;
buf : UNTRACED POINTER TO SYS.BYTE;
BEGIN
IF soundBuf=NIL THEN RETURN FALSE END;
file := d.Open(filePath,d.oldFile);
IF file#NIL THEN
d.OldClose(file);
IF ~Request("Overwrite file?","Ok","Cancel") THEN RETURN TRUE END;
END;
bodySize := (oneShotHi+repeatHi) * 31;
file := d.Open(filePath,d.newFile);
IF file=NIL THEN RETURN FALSE END;
vhdr.oneShotHiSamples := oneShotHi;
vhdr.repeatHiSamples := repeatHi;
vhdr.samplesPerHiCycle := 0;
vhdr.samplesPerSec := 8363;
vhdr.ctOctave := 5;
vhdr.sCompression := 0;
vhdr.volume.hi := 1; vhdr.volume.lo := 0;
ip.Busy(win);
LOOP
size := 4 + SIZE(vhdr)+8 + 22+8 + bodySize+8;
IF (d.Write(file,"FORM",4)<4) OR
(d.Write(file,size,4) <4) OR
(d.Write(file,"8SVX",4)<4) THEN EXIT END;
size := SIZE(vhdr);
IF (d.Write(file,"VHDR",4)<4) OR
(d.Write(file,size,4) <4) OR
(d.Write(file,vhdr,SIZE(vhdr))<SIZE(vhdr)) THEN EXIT END;
size := 22;
IF (d.Write(file,"ANNO",4)<4) OR
(d.Write(file,size,4) <4) OR
(d.Write(file,"Generated by FMsynth\o\o",22)<22) THEN EXIT END;
IF (d.Write(file,"BODY",4) <4) OR
(d.Write(file,bodySize,4)<4) THEN EXIT END;
i := 5; WHILE i >= 1 DO
buf := Buffer(i);
len := SYS.LSH(repeatHi+oneShotHi,5-i);
IF d.Write(file,buf^,len) < len THEN EXIT END;
DEC(i) END;
ip.Normal(win);
d.OldClose(file);
RETURN TRUE;
END;
ip.Normal(win);
d.OldClose(file);
RETURN FALSE
END Save8SVX;
(*------------------------------------------------------------------------*)
PROCEDURE SaveVoice(filePath:ARRAY OF CHAR):BOOLEAN; (* $CopyArrays- *)
VAR i : INTEGER;
PROCEDURE Write(dat: ARRAY OF SYS.BYTE): BOOLEAN; (* $CopyArrays- *)
BEGIN RETURN d.Write(file,dat,LEN(dat)) < LEN(dat) END Write;
BEGIN
file := d.Open(filePath,d.oldFile);
IF file#NIL THEN
d.OldClose(file);
IF ~Request("Overwrite file?","Ok","Cancel") THEN RETURN TRUE END;
END;
file := d.Open(filePath,d.newFile);
IF file=NIL THEN RETURN FALSE END;
ip.Busy(win);
LOOP
IF d.Write(file,"FMsy",4) < 4 THEN EXIT END;
IF d.Write(file," 1.0",4) < 4 THEN EXIT END;
FOR i := 0 TO 5 DO
IF Write(op[i]) THEN EXIT END;
END;
IF Write(oneShotHi) OR
Write(repeatHi) OR
Write(algo) OR
Write(lfo) OR
Write(transp) OR
Write(soundLen) OR
Write(feedback) OR
Write(filter) OR
Write(mode) OR
Write(Per) OR
Write(rRate) THEN EXIT
END;
ip.Normal(win);
d.OldClose(file);
SetName(filePath);
RETURN TRUE;
END;
d.OldClose(file);
ip.Normal(win);
RETURN FALSE;
END SaveVoice;
(*------------------------------------------------------------------------*)
PROCEDURE LoadVoice(filePath:ARRAY OF CHAR):BOOLEAN; (* $CopyArrays- *)
VAR i : INTEGER;
head: LONGINT;
PROCEDURE Read(VAR dat: ARRAY OF SYS.BYTE): BOOLEAN;
BEGIN RETURN d.Read(file,dat,LEN(dat)) < LEN(dat) END Read;
BEGIN
file := d.Open(filePath,d.oldFile);
IF file=NIL THEN RETURN FALSE END;
ip.Busy(win);
LOOP
IF d.Read(file,head,4) < 4 THEN EXIT END;
IF head # SYS.VAL(LONGINT,"FMsy") THEN EXIT END;
IF d.Read(file,head,4) < 4 THEN EXIT END;
IF head # SYS.VAL(LONGINT," 1.0") THEN EXIT END;
FOR i:=0 TO 5 DO
IF Read(op[i]) THEN EXIT END;
END;
IF Read(oneShotHi) OR
Read(repeatHi) OR
Read(algo) OR
Read(lfo) OR
Read(transp) OR
Read(soundLen) OR
Read(feedback) OR
Read(filter) OR
Read(mode) OR
Read(Per) OR
Read(rRate) THEN EXIT
END;
ip.Normal(win);
Refresh;
d.OldClose(file);
SetName(filePath);
ResetChord;
RETURN TRUE;
END;
d.OldClose(file);
ip.Normal(win);
Refresh;
RETURN FALSE;
END LoadVoice;
(*------------------------------------------------------------------------*)
PROCEDURE New;
VAR i: INTEGER;
BEGIN
FOR i:=0 TO 5 DO InitOp(i) END;
algo.numLines := 0;
transp := 1.0;
shiftOct := 0;
lfo.wave:=sin; lfo.spd:=0; lfo.del:=0; lfo.amd:=0; lfo.pmd:=0;
lastWas:=none; flag:=FALSE;
opNr:=0;
soundLen := 15996;
Per := 226;
rRate:=127;
feedback:=0;
filter:=FALSE;
mode:=poly;
Refresh;
LoopsOff;
scrtitle[13] := CHR(shiftOct+ORD("1"));
SetName("Unnamed");
ResetChord;
END New;
(*------------------------------------------------------------------------*)
PROCEDURE SoundStop;
VAR ch: SHORTINT;
BEGIN
FOR ch := as.left0 TO as.left1 DO
as.StopSound(ch);
state[ch] := end;
END
END SoundStop;
(*------------------------------------------------------------------------*)
PROCEDURE CheckMenu;
VAR menuCode,menuNr,itemNr,subNr:INTEGER;
item:I.MenuItemPtr;
changed: BOOLEAN;
BEGIN
changed := FALSE;
menuCode:=mes.code;
WHILE menuCode # I.menuNull DO
item := I.ItemAddress(menu^,menuCode);
menuNr := I.MenuNum(menuCode);
itemNr := I.ItemNum(menuCode);
subNr := I.SubNum(menuCode);
CASE menuNr OF
| 0:
IF (itemNr=0) & DoFileRequest("Load Voice",filePath) THEN
IF ~LoadVoice(filePath) & Request("Can't load voice","","Cancel") THEN END;
END;
IF (itemNr=1) & DoFileRequest("Save Voice",filePath) THEN
IF ~SaveVoice(filePath) & Request("Can't save voice","","Cancel") THEN END;
END;
IF (itemNr=2) & DoFileRequest("Save 8SVX",filePath) THEN
IF ~Save8SVX(filePath) & Request("Can't save sound","","Cancel") THEN END;
END;
IF (itemNr=3) & Request("Are you sure?","Yes","No") THEN New END;
IF (itemNr=5) & Request("Really quit?","Ok","Cancel") THEN SoundStop; HALT(0) END;
| 1:
IF itemNr=0 THEN InitOp(opNr); SetOp(opNr) END;
IF (itemNr=1) & (subNr>=0) & (subNr<=5) THEN
op[subNr] := op[opNr];
changed := TRUE;
END;
IF itemNr=2 THEN
CASE subNr OF
| 0: IF op[opNr].freq <= 49999.0 THEN
op[opNr].freq:=op[opNr].freq*2;SetREALGad(gadFreq,op[opNr].freq);
changed := TRUE;
END;
| 1: IF op[opNr].freq >= 0.0002 THEN
op[opNr].freq:=op[opNr].freq/2;SetREALGad(gadFreq,op[opNr].freq);
changed := TRUE;
END;
ELSE
END
END;
| 2:
IF itemNr=0 THEN
CASE subNr OF
| 0: algo.numLines:=0;
| 1: algo.numLines:=3; SetLine(1,2,1); SetLine(2,4,3); SetLine(3,6,5);
| 2: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,2); SetLine(3,5,4); SetLine(4,6,5);
| 3: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,1); SetLine(3,4,3); SetLine(4,6,5);
| 4: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,2); SetLine(3,4,2); SetLine(4,6,5);
| 5: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,2); SetLine(3,4,3); SetLine(4,6,5);
| 6: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,2); SetLine(3,5,4); SetLine(4,6,4);
| 7: algo.numLines:=4; SetLine(1,2,1); SetLine(2,6,3); SetLine(3,6,4); SetLine(4,6,5);
| 8: algo.numLines:=4; SetLine(1,2,1); SetLine(2,3,1); SetLine(3,5,4); SetLine(4,6,4);
| 9: algo.numLines:=5; SetLine(1,2,1); SetLine(2,3,2); SetLine(3,4,3); SetLine(4,5,4); SetLine(5,6,5);
ELSE
END;
DrawAlgo;
changed := TRUE;
END;
IF itemNr=1 THEN
IF (subNr >= 0) & (subNr < numChords) THEN chord := subNr END;
END;
IF itemNr=2 THEN SetLoop END;
IF itemNr=3 THEN FourierAnalysis END;
IF itemNr=4 THEN autoCalc := I.checked IN item.flags END;
ELSE
END;
menuCode := item.nextSelect
END;
IF changed & autoCalc THEN CalcSound() END;
END CheckMenu;
(*------------------------------------------------------------------------*)
(* $SaveRegs+ $StackChk- *)
PROCEDURE InterruptProc;
VAR volMod : INTEGER;
perMod : INTEGER;
ch : SHORTINT;
BEGIN
(* $NilChk- $OvflChk- $RangeChk- *)
SYS.SETREG(13,SYS.REG(9));
IF ~disabled THEN
FOR ch:=as.left0 TO as.left1 DO
IF delay[ch]>0 THEN DEC(delay[ch]) END;
IF state[ch] # end THEN
IF state[ch] = keyUp THEN
vol[ch] := vol[ch]-deltaVol;
IF vol[ch] <= 0.0 THEN
vol[ch] := 0.0;
state[ch] := end;
END;
END;
volTemp := vol[ch];
perTemp := per[ch];
IF delay[ch]=0 THEN
INC(lfoArg[ch],lfoInc);
END;
IF lfo.amd>0 THEN (* Modulate volume *)
volTemp := volTemp * (1.0-lfo.amd*((128+LONG(lfoTab[SYS.LSH(lfoArg[ch],-8)]))/32768.0));
END;
IF lfo.pmd>0 THEN (* Modulate period *)
perTemp := perTemp * (1.0+lfo.pmd*((128+LONG(lfoTab[SYS.LSH(lfoArg[ch],-8)]))/maxPM));
END;
volMod := SHORT(ffp.Fix(volTemp+0.5));
perMod := SHORT(ffp.Fix(perTemp+0.5));
as.ModifySound(ch,perMod,volMod);
END;
END;
END;
(* $NilChk= $OvflChk= $RangeChk= *)
END InterruptProc;
(* $StackChk= *)
(*------------------------------------------------------------------------*)
PROCEDURE HandleVertGad(gad: I.GadgetPtr; new:BOOLEAN): SHORTINT;
VAR val: INTEGER;
BEGIN
val := 127-is.VertPot(gad,128);
IF new THEN is.SetProp(gad,win,NIL,0,127-val,0,128) END;
ShowPot(rp,gad);
RETURN SHORT(val);
END HandleVertGad;
(*------------------------------------------------------------------------*)
PROCEDURE HandleHorizGad(gad: I.GadgetPtr): SHORTINT;
VAR val: INTEGER;
BEGIN
val := is.HorizPot(gad,128);
is.SetProp(gad,win,NIL,val,0,128,0);
RETURN SHORT(val);
END HandleHorizGad;
(*------------------------------------------------------------------------*)
BEGIN
(*
win:=NIL; win2:=NIL; scr:=NIL; menu:=NIL; req:=NIL;
gadOffs:=NIL; gadClr:=NIL;
soundBuf := NIL; soundLen := 0;
intOn:=FALSE;
FOR i:=1 TO 5 DO gadBuf[i]:=NIL END;
*)
SYS.SETREG(0,SYS.ADR(ver));
me := SYS.VAL(SYS.ADDRESS,ol.Me);
oldWindowPtr := me.windowPtr;
oldfltstate := as.CheckFilter();
IF ol.OldSP.stackSize<4000 THEN HALT(d.error) END;
lfoPic := ToChipMem(SYS.VAL(SYS.ADDRESS,LFOPics),16,FALSE);
mixPic := ToChipMem(SYS.VAL(SYS.ADDRESS,MixPics),12,FALSE);
lfoImg := is.CreateImage(0,0,16,8,1,lfoPic^,SHORTSET{1},SHORTSET{0},NIL);
mixImg := is.CreateImage(0,0,16,6,1,mixPic^,SHORTSET{1},SHORTSET{0},NIL);
fmPic := ToChipMem(SYS.VAL(SYS.ADDRESS,FMPic),864,TRUE);
fmImg := is.CreateImage(27,0,117,27,2,fmPic^,SHORTSET{0,1},SHORTSET{},NIL);
zifPic := ToChipMem(SYS.VAL(SYS.ADDRESS,Ziffern),10,FALSE);
zifImg := is.CreateImage(0,0,2,5,1,zifPic^,SHORTSET{1},SHORTSET{0},NIL);
as.SetPriority(20);
IF (as.OpenChannel({as.left0 })<0) OR
(as.OpenChannel({as.right0})<0) OR
(as.OpenChannel({as.right1})<0) OR
(as.OpenChannel({as.left1 })<0) THEN rq.Fail("Can't open audio channel") END;
SetUpScreen;
New;
SetKeys;
int.node.type := e.interrupt;
int.node.pri := 0;
int.node.name := NIL;
int.data := SYS.REG(13);
int.code := InterruptProc;
SoundStop;
chan:=as.left0;
cia.base := e.OpenResource(cia.ciaaName);
rq.Assert(cia.base # NIL,"Can't open ciaa.resource");
rq.Assert(cia.AddICRVector(hw.ta,SYS.ADR(int))=NIL,"CIAA Timer A in use");
hw.ciaa.cra := SHORTSET{};
intOn:=TRUE;
SetTimer(TRUE);
is.msgFilter := LONGSET{I.mouseMove};
LOOP
is.GetIMsg(win,mes,TRUE);
IF (I.rawKey IN mes.class) & ~(ie.repeat IN mes.qualifier) THEN
code := mes.code;
CASE code OF
64: SoundStop| (* Space *)
80..84: shiftOct := code-80; (* F1 - F5 *)
scrtitle[13] := CHR(shiftOct+ORD("1"));
I.SetWindowTitles(win,-1,SYS.ADR(scrtitle))|
ELSE
IF code<128 THEN (* Key down *)
keyCode := key[code];
IF keyCode >= 0 THEN
octave := keyCode DIV 12 + shiftOct + 1;
IF (octave<=5) & (soundBuf # NIL) THEN
disabled := TRUE;
per[chan] := period[keyCode];
vol[chan] := 64.0;
delay[chan] := LONG(lfo.del) * 2;
lfoArg[chan]:= 0;
perTemp := per[chan];
volTemp := vol[chan];
IF lfo.amd>0 THEN
volTemp := volTemp * (1.0-lfo.amd*((128+LONG(lfoTab[0]))/32768.0));
END;
IF lfo.pmd>0 THEN
perTemp := perTemp * (1.0+lfo.pmd*((128+LONG(lfoTab[0]))/maxPM));
END;
as.PlayLoopSound(chan,Buffer(octave),SYS.LSH(oneShotHi,5-octave),SYS.LSH(repeatHi,5-octave),SHORT(ffp.Fix(perTemp+0.5)),SHORT(ffp.Fix(volTemp+0.5)));
state[chan] := keyDown;
channel[keyCode] := chan;
disabled := FALSE;
IF mode=poly THEN
CASE chan OF
| as.left0: chan:=as.right0
| as.right0: chan:=as.left1
| as.right1: chan:=as.left0
| as.left1: chan:=as.right1
END;
END;
MarkKey(keyCode+shiftOct*12,TRUE);
END
END
ELSE (* Key up *)
keyCode := key[code-128];
IF keyCode >= 0 THEN
state[channel[keyCode]] := keyUp;
MarkKey(keyCode+shiftOct*12,FALSE);
END
END
END
ELSIF I.menuPick IN mes.class THEN CheckMenu
ELSIF I.mouseMove IN mes.class THEN
IF (actPropGad # NIL) & (HandleVertGad(actPropGad,FALSE)=0) THEN END;
ELSIF I.gadgetDown IN mes.class THEN
actPropGad := mes.iAddress;
ELSIF I.gadgetUp IN mes.class THEN
selGad:=mes.iAddress; id:=selGad.gadgetID;
CASE id OF
| O1..O6: opNr := SHORT(id-O1);SetOp(opNr);
| R1..R4: op[opNr].r[id-R1] := HandleVertGad(gadEG[id-R1],TRUE);
IF autoCalc THEN CalcSound END;
| L1..L4: op[opNr].l[id-L1] := HandleVertGad(gadEG[id-R1],TRUE);
IF autoCalc THEN CalcSound END;
| OL: op[opNr].outp := HandleVertGad(gadOutp,TRUE);
IF autoCalc THEN CalcSound END;
| SL: op[opNr].scL := HandleVertGad(gadScL,TRUE);
IF autoCalc THEN CalcSound END;
| SR: op[opNr].scR := HandleVertGad(gadScR,TRUE);
IF autoCalc THEN CalcSound END;
| FR: GetREALGad(gadFreq,op[opNr].freq);
SetREALGad(gadFreq,op[opNr].freq);
IF autoCalc THEN CalcSound END;
| TP: GetREALGad(gadTsp,transp);
SetREALGad(gadTsp,transp);
IF autoCalc THEN CalcSound END;
| M1..M6:
lastMod := SHORT(id-M1);
IF flag THEN
IF lastWas=car THEN
CheckLine(lastMod,lastCar);
DrawAlgo;
flag := FALSE;
IF autoCalc THEN CalcSound END;
END;
ELSE
flag := TRUE
END;
lastWas := mod;
| C1..C6:
lastCar := SHORT(id-C1);
IF flag THEN
IF lastWas=mod THEN
CheckLine(lastMod,lastCar);
DrawAlgo;
flag := FALSE;
IF autoCalc THEN CalcSound END;
END;
ELSE
flag := TRUE
END;
lastWas := car;
| WA: NextLFOWave;
| SP: lfo.spd := HandleHorizGad(gadLFOs);
lfoInc := (LONG(lfo.spd)+1)*64;
| DE: lfo.del := HandleHorizGad(gadLFOd)
| AM: lfo.amd := HandleHorizGad(gadLFOa)
| PM: lfo.pmd := HandleHorizGad(gadLFOp)
| CS: IF autoCalc THEN
autoCalc := FALSE; CalcSound(); autoCalc := TRUE;
ELSE
CalcSound();
END;
| RR: rRate := SHORT(127-is.HorizPot(gadRel,128)); SetRR;
| LN: soundLen := is.GadgetVal(gadLen); GetMem; LoopsOff;
| FB: feedback := SHORT(SHORT(is.GadgetVal(gadFeed))); SetFeedback;
IF autoCalc THEN CalcSound END;
| OM: IF op[opNr].mode=ratio THEN
op[opNr].mode:=fixed
ELSE
op[opNr].mode:=ratio
END;
SetOp(opNr);
IF autoCalc THEN CalcSound END;
| PR: Per := SHORT(is.GadgetVal(gadPer)); SetPer;
| MD: IF mode=poly THEN mode := mono ELSE mode:=poly END; SetMode;
| FL: filter := ~ filter; SetFilter;
ELSE
END
END
END;
CLOSE
me.windowPtr := oldWindowPtr;
IF intOn THEN SetTimer(FALSE); cia.RemICRVector(hw.ta,SYS.ADR(int)) END;
is.DeleteWindow(win);
IF is.DeleteScreen(scr) THEN END;
as.Filter(oldfltstate);
END FMsynth.